\chapter{源码控制 \& 为什么需要她}

\section{什么是源码控制?}

一个源码控制系统是一个用于管理项目内文件的软件。项目( 例如该书或者一个软件应用  )一般包含了大量的文件。这些文件依次被组织在文件夹或者子文件夹内进行管理。在任何一个特定的时间内这些文件在编辑状态下由项目的最新版本的（文件）工作拷贝组成。如果其它的人员也在该项目里进行工作你必须将你的当前正在工作复制给他们以让他们进行工作。当他们查找并修改问题后，他们的工作拷贝将与你的工作拷贝不一样（它在一个不一样的版本里）。当你可以继续他们的工作时，你需要某种机制更新你的这些文件的工作拷贝以同步到团队工作的最新版本。一旦你更新了你的文件，这个新版本的项目还将再次执行同样的循环周期。就像是当前的版本会被编一个唯一的号码，这就是为什么书有版本软件也有版本号的原因。

当软件开发工程师在一个大型项目里和多个开发人员一起时会有这个周期且意识到他们需要一个工具来控制这些变更。当多个开发人员开发时，同一个文件将会被二个人修改并且是不一样的方向，什么被修改的记录也会丢失。在软件发布一个新版本时将会很难保证所有团队成员的BUG修复和功能增强都被包含在内。

一个叫The Source Control System\cite{SCCS}的源码控制系统在1972年由Bell Labs开发出来用于跟踪文件修改。它会记录对每一个文件的修改到一个文件内且包含关于这个修改的描述（为什么这样修改）。它同样也限制了谁可以对文件进行修改以保障不会发生编辑文件的冲突发生. \cite{USE-SCCS}

\label{versioning}这个很重要，但是开发者们会发现他们需要更多的功能。他们需要可以保存所有项目里文档的状态并且给他们一个名字（例如：Release 3.14）。 当软件项目成熟时你将不但会有一个发布版本来使用还有一个BUG报告来针对该版本，当下一个版本发布时会增加新的功能并修复之前的BUG。源码控制系统将不得不去处理这些现在叫做分支的问题。一个分支例如叫做“版本2”发布了但是却在继续修复比如版本1.1,1.2的问题。同时，你还有另外一个分支叫做“版本2”正在进行添加新功能的编码工作。

在1986年开放源代码的并发版本控制系统CVS \cite{CVS} 被开发出来。这个系统允许对一组文件添加标签而且允许同时拥有多分支（例如：版本）。当时有许多其它的版本控制系统被开发出来，有开源的也有封闭的。

在2006年发布 \cite{FOSSIL-HOME} 的Fossil是一个安装简单的版本控制系统同时还集成了问题标签系统 ( 图解 \vref{fig:viewticket}) ，一个wiki ( 图解 \vref{sub:Wiki-Use}) 还有内建一个网站服务器 ( 图解 \vref{fig:Starting-Webserver})。


\section{为何在项目里使用文档版本?}
你为什么需要使用一个源码控制系统？你无法在文件夹间随意地创建文件，删除文件，移动文件。在你的代码里进行修改时有一个需要仔细遵照的检查清单和步骤。

有这么多激辩，为什么还要做？作为一个开发人员最可怕的噩梦是 ``它昨天还工作得很好'' 综合症。是的，你已经使它工作起来了但是现在又不行了。如果你只是在一个文档内工作，可以想象的是你保存了不同名词( 可能是日期后缀 )的副本，因此你可以回退回去。但是如果你没有这样做，毫无疑问，你无法恢复到你之前的代码。如果有源码控制系统且坚持遵循其规程，你可以立即回退到昨天某个时间的代码，或者是一个小时之前的，甚至是上个月的。在你完成这些后，你开始知道什么是好的代码，你可以检查出到底发生了什么（才导致这样的结果）。

在有源码控制系统的的帮助下，你还可以自由地进行试验，“让我们试试那个激进的新技术”，如果它无法工作，那么就退回到之前的状态。

这本书的其余部分是一个Fossil版本控制系统的用户手册，用以进行代码管理甚至更多更多。它可以运行在多个操作系统之上且免费、开放源代码( FOSS协议 )。它安装非常简单只有一个可执行文件，且代码仓库只有一个文件，可以非常简单地备份并且大约只有源代码50\% 的大小（SQLite数据库压缩）。

\subsection{如何获取}
如果这些可以激起你的兴趣，你可以从\url{http://www.fossil-scm.org/download.html}获得一个Fossil可执行行文件的拷贝。该页面里有Linux、Mac和Windows系统的可执行文件的链接。如果你想要自己进行编译也可以找到源代码。该网站还包含这个PDF和这个PDF的源代码，该网站托管使用的是Fossil (查看章节\vref{sec:Multiple-Users}). 


\section{源码控制描述}
如果你没有使用过源码控制系统，那么该章节将非常有用。我将定义一些词汇并且解释下源码控制的基本理念。

\subsection{Check Out 检入检出系统}
当描述源码控制的源祖如SCCS时我说过它管理一个单一文件的变更且阻止多个人同时在同一个文件上工作。这是一个典型的全局源码控制系统。这样你可以理解“检入（check out）”一个文件并编辑它，同时同样使用该源码控制系统的人可以看到谁（也就是你）在这个文件上进行工作那么他们被禁止碰这个文件。他们可以获得一个只读的文件拷贝，那么他们说他们可以构建软件但除了那个文件，因为只有“所有者”可以编辑它。当完成编辑后，“所有者”检回那个文件，然后其它任何一个人就可以继续在该文件上工作。检回的同时系统记录了谁曾经编辑了它以及做了什么修改。

这个系统在一个可以实时沟通小的组织里工作得很好，一个常见的问题是一个文件被某个人检出了，而\textbf{你} 必须对它进行修改，在一个小团队的组织中，你只要对着房间大喊一下就可以解决这个问题。


\subsection{Merge 集中式系统}
在以CVS或Subversion为代表的系统中需要区分的是不是获取文件然后编辑而是将其推送到版本控制中去。在这些系统中你将源代码文件放到一个你本机的工作文件夹内，然后你编辑这些文件并作必要的修改，当完成时你提交或者将它们检回到代码仓库里去。如此它们回到版本控制系统中且系统知道当前版本和上一个版本之间的变化。

这个解决了上面提到的当其他人锁定的文件无法编辑的问题。你现在解决了这个问题，很多人可以同时在同一个文件上工作并且做出修改。它使用Check-In(检入)流程来处理。在某个时间点只有一个人可以Check-In一个文件。将要发生的是系统检查该文件，如果代码仓库里的文件有修改而不是你之前检入的那个文件，系统将终止检入流程，系统将会询问用户是否想要合并那些新的修改到他的拷贝中去，一旦完成操作，那么最新的版本就可以被成功检入。

这种类型的系统使用在大型项目里如Linux内核开发或者其它拥有大量不同区域分布的贡献者的项目里。

\subsection{Distributed 分布式系统}
目前为止上面我们提到的二个主要系统都是中心化的。也就是说只有一个代码仓库位于一个独立的服务器上，当你获取文件的拷贝或者检入那些文件时，它们都汇集到一个地方。这样的方式可以支持很多很多用户。一个分布式的系统是一个该类系统的扩展，它允许代码仓库分布式存在（有多个仓库）且有使它们同步的机制。

在一个独立服务器上的唯一代码仓库工作模式下，必须可以连接到该服务器以获取更新及检入最新的代码。如果你无法连接到服务器那么你就被困住了而无法继续工作。分布式系统允许你拥有自己的代码仓库拷贝然后可以在离线状态下继续工作,当你可以与服务器进行通讯时你可以与之同步。当人们把工作带回家或者无法连接到公司网络是这个就变得非常有用，每个人都可以拥有一个代码仓库可以离线工作，当回到办公室时可以重新工作内容同步到服务器。


\subsection{一般名词}
下面是当我谈论版本控制或者Fossil时需要使用的名词的一份清单。
\begin{description}
\item [{Repository}] 这个是一个保存版本控制文件的仓库，它由源码控制系统管理。
\item [{SCS}] 源码控制系统，这是一个管理一组文件并跟踪修改，允许多个用户在一个控制的规则规范下编辑它们的软件。
\item [{Commit}] 在Fossil里保存当前的新文件或者变更的文件到代码仓库里去。
\item [{Trunk}] Fossil代码仓库里的代码发展的主要线路（主分支）。
\item [{Branch}] 一个用户定义的代码分支并有SCS提供服务，它允许在一个代码仓库里有多个工作点，老分支（版本）可能有已经结束的BUG修复，新的分支（版本）可能含有添加的新功能。
\item [{Fork}] 在Fossil里是一个在代码路径里的自然而然的分叉（裂隙），当仓库里一个有修改的文件而没有被提交的时候发生。**
\end{description}
